#include "GLScene.h"

#include <iostream>
#include <math.h>

#include "sdl.h"

#include "GLSceneProjectionMode.h"
#include "GLSceneOrthogonalMode.h"
#include "GLSceneFrameAndMaskDrawers.h"
#include "GLSceneMapDrawers.h"
#include "GLSceneInterfaceDrawers.h"

namespace catan
{

GLScene::GLScene(GameState &gameState, SDLCanvas &sdlCanvas, GLTextures &glTextures, GameMap &gameMap): gameStateRef(&gameState), sdlCanvasRef(&sdlCanvas), glTexturesRef(&glTextures), gameMapRef(&gameMap), frame(0)
{
}

GLScene::~GLScene()
{
}

void GLScene::poll()
{
	SDL_Event *mouseButtonDownEvent = gameStateRef->pollMouseButtonDownEvent();
	if (mouseButtonDownEvent != NULL)
	{
		click(mouseButtonDownEvent->button.x, mouseButtonDownEvent->button.y);
	}
	SDL_Event *mouseMotionEvent = gameStateRef->pollMouseMotionEvent();
	if (mouseMotionEvent != NULL)
	{
		int x = mouseMotionEvent->button.x;
		int y = mouseMotionEvent->button.y;
		float xRatio = (sdlCanvasRef->getWindowUnitWidth() - sdlCanvasRef->getClientUnitWidth())/2;
		float yRatio = (sdlCanvasRef->getWindowUnitHeight() - sdlCanvasRef->getClientUnitHeight())/2;
		float clientX = (x - xRatio*sdlCanvasRef->getWidth())*(sdlCanvasRef->getWindowUnitWidth()/sdlCanvasRef->getWidth());
		float clientY = (y - yRatio*sdlCanvasRef->getHeight())*(sdlCanvasRef->getWindowUnitHeight()/sdlCanvasRef->getHeight());
		float calcX = (0.4f-clientX)/(0.09375f*clientY + 0.1335f);
		//float calcY = (9.107f*clientY*clientY - 18.486f*clientY + 3.687f);
		//-3.8008346998012343 + 20.05063303391713x -15.795532422655647x^2 + 8.878439171845189x^3
		float calcY = 8.878439171845189*clientY*clientY*clientY - 15.795532422655647*clientY*clientY + 20.05063303391713*clientY - 3.8008346998012343; 
		float calcX2 = -calcX*2 + 3;
		float calcY2 = calcY + calcX + 3;
		float offsetXs[6] = {0.6667f, 0.3333f, -0.3333f, -0.6667f, -0.3333f, 0.3333f};
		float offsetYs[6] = {-0.3333f, -0.6667f, -0.3333f, 0.3333f, 0.6667f, 0.3333f};
		for (int j=0; j<6; ++j)
		{
			for (int i=0; i<6; ++i)
			{
				for (int k=0; k<6; ++k)
				{
					if (calcX2 > (i+offsetXs[k])-0.1f && calcX2 < (i+offsetXs[k])+0.1f &&
					    calcY2 > (j+offsetYs[k])-0.1f && calcY2 < (j+offsetYs[k])+0.1f)
					{
						std::cout << "Match found at (" << i << ", " << j << ", " << k << "): real: " << calcX2 << ", " << calcY2 << "; goal: " << (i+offsetXs[k]) << ", " << (j+offsetYs[k]) << std::endl;
					}
				}
			}
		}
	}
}

void GLScene::draw()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	if (gameStateRef->getAreHexagonsDrawn() || gameStateRef->getIsBackgroundDrawn())
	{
		GLSceneProjectionMode::begin(*sdlCanvasRef, -0.2f, 0.0f);
	    	glPushMatrix();
		        glTranslatef(0.0f, 0.15f, 0.0f);
		        glTranslatef(0.0f, 0.0f, -1.0f);
		        //glTranslatef(0.0f, -0.15f, 0.0f);
		        glRotatef(30.0f, 1.0f, 0.0f, 0.0f);
		        glScalef(0.75f, 0.75f, 0.75f);
		        glTranslatef(0.0f, -0.5f, 0.0f);
		    	if (gameStateRef->getAreHexagonsDrawn())
		    	{
		    		GLSceneMapDrawers::drawHexagons(1.0f, *glTexturesRef, *gameMapRef, settlements, settlementColors, roads, roadColors);
		    	}
		    	if (gameStateRef->getIsBackgroundDrawn())
		    	{
		    		GLSceneMapDrawers::drawBackground(1.5f, glTexturesRef->getSeaTexture());
		    	}
	    	glPopMatrix();
		GLSceneProjectionMode::end();
	}
	if (gameStateRef->getIsMaskDrawn())
	{
	    glClear(GL_DEPTH_BUFFER_BIT);
		GLSceneOrthogonalMode::begin(*sdlCanvasRef);
			GLSceneFrameAndMaskDrawers::drawOrthogonalMaskAroundClient(*sdlCanvasRef);
			GLSceneFrameAndMaskDrawers::drawOrthogonalMaskAroundMapArea(0.0f, 0.2f, 0.3f, 0.0f, *sdlCanvasRef);
		GLSceneOrthogonalMode::end();
	}
    if (gameStateRef->getIsFrameDrawn())
    {
        glClear(GL_DEPTH_BUFFER_BIT);
	    if ((frame%2)==0)
	    {
			GLSceneProjectionMode::begin(*sdlCanvasRef, 0.0f, 0.0f);
				GLSceneFrameAndMaskDrawers::drawProjectionFrameAroundClient(*sdlCanvasRef);
			GLSceneProjectionMode::end();
	    }
	    else
	    {
			GLSceneOrthogonalMode::begin(*sdlCanvasRef);
			GLSceneFrameAndMaskDrawers::drawOrthogonalFrameAroundClient(*sdlCanvasRef);
	    	GLSceneOrthogonalMode::end();
	    }
	    glClear(GL_DEPTH_BUFFER_BIT);
    }
    if (gameStateRef->getIsPreStartGame())
    {
    	glClear(GL_DEPTH_BUFFER_BIT);
		GLSceneOrthogonalMode::begin(*sdlCanvasRef);
			GLSceneInterfaceDrawers::drawButton(0.8f, 1.0f, 0.05f, 0.0f, glTexturesRef->getRandomizeTexture(), *sdlCanvasRef);
			GLSceneInterfaceDrawers::drawButton(0.8f, 1.0f, 0.10f, 0.05f, glTexturesRef->getStartGameTexture(), *sdlCanvasRef);
		GLSceneOrthogonalMode::end();
    }
    SDL_GL_SwapBuffers();
    if (timer.secondsSinceReference() > 1.0f)
    {
    	frame++;
    	timer.resetReference();
    }
}

void GLScene::click(int x, int y)
{
	//y equation, for x=1 to 15: 0.6054460246*x^2 + 19.63446994*x + 13.52352941
	//0.606, 19.6, 13.5

	float xRatio = (sdlCanvasRef->getWindowUnitWidth() - sdlCanvasRef->getClientUnitWidth())/2;
	float yRatio = (sdlCanvasRef->getWindowUnitHeight() - sdlCanvasRef->getClientUnitHeight())/2;
	float clientX = (x - xRatio*sdlCanvasRef->getWidth())*(sdlCanvasRef->getWindowUnitWidth()/sdlCanvasRef->getWidth());
	float clientY = (y - yRatio*sdlCanvasRef->getHeight())*(sdlCanvasRef->getWindowUnitHeight()/sdlCanvasRef->getHeight());
	float clientYToUnit = clientY * 4 / 3;
	if (gameStateRef->getIsPreStartGame())
	{
		if (clientX > 0.8f && clientX < 1.0f &&
				clientYToUnit > 0.0f && clientYToUnit < 0.05f)
		{
			gameMapRef->reset();
		}
		else if (clientX > 0.8f && clientX < 1.0f &&
				clientYToUnit > 0.05f && clientYToUnit < 0.10f)
		{
			gameStateRef->setIsPreStartGame(false);
		}
		else
		{
			float calcX = (0.4f-clientX)/(0.09375f*clientY + 0.1335f);
			//float calcY = (9.107f*clientY*clientY - 18.486f*clientY + 3.687f);
			//-3.8008346998012343 + 20.05063303391713x -15.795532422655647x^2 + 8.878439171845189x^3
			float calcY = 8.878439171845189*clientY*clientY*clientY - 15.795532422655647*clientY*clientY + 20.05063303391713*clientY - 3.8008346998012343; 
			float calcX2 = -calcX*2 + 3;
			float calcY2 = calcY + calcX + 3;
			std::cout << clientX << ", " << clientY << "; " << calcX << ", " << calcY << "; " << calcX2 << ", " << calcY2 << std::endl;
		}
	}
	else
	{
		//float persX = (-5374.1584f*clientY+1125.344005f);
		//float persX = (-0.150219f * clientYToUnit + 0.228842f)*(1/1.25);
		//float persX = -0.979205f*clientYToUnit + 0.628562f;
		//float persX = -0.120175f*clientYToUnit + 0.183074f;
		//float persX = -0.119863*clientYToUnit - 0.215068f;
		//float mid = 0.4f;
		//std::cout << "G" << clientX-mid << " " << clientYToUnit << " " << persX << std::endl;
		if (clientX < 0.5f)
		{
			queryAddRoad();
		}
		else
		{
			queryAddSettlement();
		}
	}
}

void GLScene::queryAddRoad()
{
	int x;
	int y;
	int loc;
	int color;
	std::cout << "Adding a road." << std::endl;
	std::cout << "x: ";
	std::cin >> x;
	std::cout << "y: ";
	std::cin >> y;
	std::cout << "tr=30, tl=150, bc=270: ";
	std::cin >> loc;
	std::cout << "red=0, green=1, blue=2, yellow=3: ";
	std::cin >> color;
	PathCoordinate pathCoordinate = PathCoordinate(CoordinateX((CoordinateX::Enum_CoordinateX)x), CoordinateY((CoordinateY::Enum_CoordinateY)y), VerticalCardinal((VerticalCardinal::Enum_VerticalCardinal)loc));
	roads.push_back(pathCoordinate);
	roadColors.insert(std::make_pair(pathCoordinate, color));
}
void GLScene::queryAddSettlement()
{
	int x;
	int y;
	int loc;
	int color;
	std::cout << "Adding a settlement." << std::endl;
	std::cout << "x: ";
	std::cin >> x;
	std::cout << "y: ";
	std::cin >> y;
	std::cout << "cr=0, cr=180: ";
	std::cin >> loc;
	std::cout << "red=0, green=1, blue=2, yellow=3: ";
	std::cin >> color;
	SiteCoordinate siteCoordinate = SiteCoordinate(CoordinateX((CoordinateX::Enum_CoordinateX)x), CoordinateY((CoordinateY::Enum_CoordinateY)y), HorizontalCardinal((HorizontalCardinal::Enum_HorizontalCardinal)loc));
	settlements.push_back(siteCoordinate);
	settlementColors.insert(std::make_pair(siteCoordinate, color));
}

}
